/*******************************************************************************
 * Copyright (c) 2008, 2009 Fabio Mauro - Alberto Terraneo.
 * Permission is granted to copy, distribute and/or modify this document
 * under the terms of the GNU Free Documentation License, Version 1.2
 * or any later version published by the Free Software Foundation.
 *     
 * This program is distributed in the hope that it will be useful, 
 * but WITHOUT ANY WARRANTY; without even the implied 
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
 * See the GNU Free Documentation License for more details.
 *     
 * You should have received a copy of the GNU Free Documentation 
 * License along with this distribution; if not, send a email to authors:
 * aterraneo <at> users.sourceforge.net
 * bigmoby09 <at> users.sourceforge.net
 *******************************************************************************/
/**
 * 
 */
package it.blueocean.acanto.dao.common;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.inject.Named;

import org.hibernate.FetchMode;
import org.hibernate.LockMode;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Example;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

/**
 * @author Fabio Mauro
 * 
 */
public abstract class AGenericDaoHibernate<T, KeyType extends Serializable> extends HibernateDaoSupport implements
		IGenericDao<T, KeyType>
{
	@Inject
	@Named("sessionFactory")
	private SessionFactory sessionFactory;
	
	@PostConstruct
	protected void initialize()
	{
		super.setSessionFactory(sessionFactory);
	}
	
	private Class<T> persistentClass;

	@SuppressWarnings("unchecked")
	public AGenericDaoHibernate()
	{
		this.persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass())
				.getActualTypeArguments()[0];
	}

	public Class<T> getPersistentClass()
	{
		return persistentClass;
	}

	public T findById(KeyType id, boolean lock)
	{
		if(lock)
			return (T) getHibernateTemplate().get(getPersistentClass(), id, LockMode.PESSIMISTIC_WRITE);
		else
			return (T) getHibernateTemplate().get(getPersistentClass(), id);
	}

	@SuppressWarnings("unchecked")
	public List<T> findByExample(T exampleInstance, List<String> excludeProperty)
	{
		DetachedCriteria criteria = DetachedCriteria.forClass(getPersistentClass());

		Example example = Example.create(exampleInstance);

		for (String exclude : excludeProperty)
		{
			example.excludeProperty(exclude);
		}

		criteria.add(example);

		return getHibernateTemplate().findByCriteria(criteria);
	}

	public T makePersistent(T entity)
	{
		getHibernateTemplate().saveOrUpdate(entity);

		return entity;
	}

	public void makeTransient(T entity)
	{
		getHibernateTemplate().delete(entity);
	}

	public void flush()
	{
		getSession().flush();
	}

	public void clear()
	{
		getSession().clear();
	}

	@SuppressWarnings("unchecked")
	public List<T> findByCriteria(List<Criterion> criterion)
	{
		DetachedCriteria criteria = DetachedCriteria.forClass(getPersistentClass());

		if(criterion != null)
		{
			for (Criterion c : criterion)
			{
				criteria.add(c);
			}
		}

		return getHibernateTemplate().findByCriteria(criteria);
	}
	
	@SuppressWarnings("unchecked")
	public List<T> findAll()
	{
		DetachedCriteria criteria = DetachedCriteria.forClass(getPersistentClass());
		return getHibernateTemplate().findByCriteria(criteria);
	}
	
	@SuppressWarnings("unchecked")
	public List<T> findAll(String... eagerAttribute)
	{
		DetachedCriteria criteria = DetachedCriteria.forClass(getPersistentClass());
		
		for (String attribute : eagerAttribute)
		{
			criteria.setFetchMode(attribute, FetchMode.JOIN);
		}
		
		return getHibernateTemplate().findByCriteria(criteria);
	}

	@SuppressWarnings("unchecked")
	public List<T> findByQuery(String hqlQuery, Object value)
	{
		if(value == null)
		{
			return getHibernateTemplate().find(hqlQuery);
		}

		return getHibernateTemplate().find(hqlQuery, value);
	}
	
	@SuppressWarnings("unchecked")
	public List<T> paginatedResult(int start, int limit)
	{
		DetachedCriteria criteria = DetachedCriteria.forClass(getPersistentClass());
		
		return getHibernateTemplate().findByCriteria(criteria,start,limit);
	}

}
